#include "Grid.h"


Grid::Grid (int rMax, int cMax, int stype) : PrimitiveObject (stype)
{
   rowMax = rMax;
   colMax = cMax;
   indexID = 0;
   numCoords = (rowMax + 1)*(colMax + 1);
   numIndex = 6 * rowMax*colMax;
   structType = stype;
}

void Grid::fill ()
{
   if (structType == Vertex::type::P_N_AND_T) {
      //@TODO
      coordDataNC = new Vertex::PNT[numCoords];      
   }
   else if (structType == Vertex::type::P_AND_N) {      
      coordDataN = new Vertex::PN[numCoords];
      for (int j = 0; j <= rowMax; j++) {
         for (int i = 0; i <= colMax; i++) {
            int k = index (i, j);
            coordDataN[k].v = glm::vec3 ((float)i / colMax - (0.5f), (float)j / rowMax - (0.5f), 0);
            coordDataN[k].n = glm::vec3 (0, 0, 1.0f);            
         }
      }
   }
   else {
      coordData = new glm::vec3[numCoords];
      for (int j = 0; j <= rowMax; j++) {
         for (int i = 0; i <= colMax; i++) {
            int k = index (i, j);
            coordData[k] = glm::vec3 ((float)i / colMax - (0.5f), (float)j / rowMax - (0.5f), 0);
         }
      }
   }

   indexData = new GLuint[numIndex];
   int k = 0;
   for (int j = 0; j < rowMax; j++) {
      for (int i = 0; i < colMax; i++) {
         indexData[k++] = index (i, j);
         indexData[k++] = index (i + 1, j + 1);
         indexData[k++] = index (i, j + 1);
         indexData[k++] = index (i, j);
         indexData[k++] = index (i + 1, j);
         indexData[k++] = index (i + 1, j + 1);
         //printf ("[%d] %d %d %d %d %d\n",k, indexData[k - 5], indexData[k - 4], indexData[k - 3], indexData[k - 2], indexData[k - 1]);
      }
   }
}

void Grid::genBuffer ()
{
   if (GLEW_VERSION_3_3) {
      glGenVertexArrays (1, &VAOHandle);
      glBindVertexArray (VAOHandle);
   }
   if (structType == Vertex::type::P_N_AND_T) {
      //@TODO
   }
   else if (structType == Vertex::type::P_AND_N) {
      glGenBuffers (1, &vertexID);
      glBindBuffer (GL_ARRAY_BUFFER, vertexID);
      glBufferData (GL_ARRAY_BUFFER, numCoords*sizeof(Vertex::PN), coordDataN, GL_STATIC_DRAW);

      glEnableVertexAttribArray (attribLoc[0]); //position in shader
      glEnableVertexAttribArray (attribLoc[1]); //normal
      glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex::PN), 0);
      glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex::PN), (GLvoid*)(sizeof(coordDataN[0].n)));
   }
   else {
      glGenBuffers (1, &vertexID);
      glBindBuffer (GL_ARRAY_BUFFER, vertexID);
      glBufferData (GL_ARRAY_BUFFER, numCoords*sizeof(glm::vec3), coordData, GL_STATIC_DRAW);

      glEnableVertexAttribArray (attribLoc[0]);
      glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), NULL);
   }
   glGenBuffers (1, &indexID);
   glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexID);
   glBufferData (GL_ELEMENT_ARRAY_BUFFER, numIndex*sizeof(GLuint), indexData, GL_STATIC_DRAW);

   if (GLEW_VERSION_3_3) {      
      glBindVertexArray (0);//free Bind
   }
}

void Grid::init (void)
{
   fill ();
   genBuffer ();
}

void Grid::draw ()
{
   glBindVertexArray (VAOHandle);
   glDrawElements (GL_TRIANGLES, numIndex, GL_UNSIGNED_INT, NULL);
   glBindVertexArray (0);
}
void Grid::drawOld (void)
{
   glBindBuffer (GL_ARRAY_BUFFER, vertexID);
   glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indexID);

   glEnableClientState (GL_NORMAL_ARRAY);
   glEnableClientState (GL_VERTEX_ARRAY);

   glNormalPointer (GL_FLOAT, sizeof(Vertex::PN), (GLvoid*)(sizeof(coordDataN[0].n)));
   glVertexPointer (3,GL_FLOAT, sizeof(Vertex::PN), NULL);
   
   glDrawElements (GL_TRIANGLES, numIndex, GL_UNSIGNED_INT, NULL);

   glDisableClientState (GL_NORMAL_ARRAY);
   glDisableClientState (GL_VERTEX_ARRAY);
}
//@TODO - Review delete
void Grid::freeBuffer ()
{
   if (structType == Vertex::type::P_N_AND_T) {
      //@TODO
   }
   else if (structType == Vertex::type::P_AND_N) {
      //@TODO
   }
   else {
      glDeleteBuffers (1, &vertexID);
      glDeleteBuffers (1, &indexID);
   }
}

int Grid::index (int i, int j)
{
   return i + j*(colMax + 1);
}

Grid::~Grid ()
{
   free (coordData);
   free (indexData);
   freeBuffer ();
}

//Using VBO
/*
void Grid::genBuffer ()
{
glGenBuffers (1, &coordId);
glBindBuffer (GL_ARRAY_BUFFER, coordId);
glBufferData (GL_ARRAY_BUFFER, numCoords*sizeof(glm::vec3), coordData, GL_DYNAMIC_DRAW);

glGenBuffers (1, &indId);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indId);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, numIndex*sizeof(GLuint), indexData, GL_STATIC_DRAW);

}

void Grid::render ()
{
glBindBuffer (GL_ARRAY_BUFFER, coordId);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indId);

glEnableClientState (GL_VERTEX_ARRAY);

glVertexPointer (3, GL_FLOAT, 0, NULL);

glDrawElements (GL_LINE_STRIP, numIndex, GL_UNSIGNED_INT, NULL);

glDisableClientState (GL_VERTEX_ARRAY);

glBindBuffer (GL_ARRAY_BUFFER, 0);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
}
*/

//Using VertexArray
/*
void Grid::render ()
{
glEnableClientState (GL_VERTEX_ARRAY);
glVertexPointer (3, GL_FLOAT, 0, glm::value_ptr (coordData[0]));
glDrawElements (GL_LINE_STRIP, 6 * (rowMax)*(colMax), GL_UNSIGNED_INT, indexData);
glDisableClientState (GL_VERTEX_ARRAY);
}
*/
